
--[[
	消息处理
    房间管理

    desk = {
        service = service,
        id = tid,
        rid = rid,
        rtype = rtype,
        user_num = 0, 总人数
        seat_num = 0, 在座位上的人数
         }
--]]
local cjson = require("cjson")
local table_insert = table.insert

---------------------------------------------------------
-- class
---------------------------------------------------------
local Handler = class("Handler")

function Handler:ctor(name)

    self.start_time = tostring(g.time()) --初始桌子id
    self.index_id = 100
    --room -> desk
    g.user_desk = {} --{uid-> {desk_id}} 玩家所在的房间
    self.lock_desk = false --
    self.closed = false --是否关闭游戏

    self:register()
end

function Handler:register()

    g.register("C2_TS_enter", handler(self, self.reqEnterDesk)) --进入桌子

    g.register("user_leave", handler(self, self.onUserLeave)) --玩家离开桌子
    g.register("get_user_desks", handler(self, self.onGetUserDesks)) --取玩家所在桌子
    g.register("disconnect", handler(self, self.onDisconnect)) --离线了
    g.register("update_desk", handler(self, self.onUpdateDesk)) --更新桌子信息
    g.register("close_game", handler(self, self.onClose)) --关闭游戏桌子
    g.register("kick_user", handler(self, self.onKickUser)) --踢玩下离开桌子
    g.register("merge_desk", handler(self, self.onMergeDesk)) --合并桌子
    g.register("user_login", handler(self, self.onUserLogin)) --玩家登录了

    --默认游戏消息处理
    g.defCallback(self, self.defaultCallback)

    --重新加载配置
    if g.room_cfg then
        g.fork(function ()
            self:loadConfig()
        end)
    end

end

function Handler:onStart()
    self:loadConfig()

    --定时清理无人桌子, 无人桌子不能太多
    g.loop(g.const.room.clear_desk_time*100, function()
        self:clearIdleDesk()
    end)
end

--加载配置
function Handler:loadConfig()
    print("begin loadConfig")
    --读取房间配置
    g.room_cfg = g.dp:getRoomConfig() -- (room_id, cfg)
    g.blind_cfg = g.dp:getBlindConfig() --盲注配置
    g.sendConfig("set", "room_cfg", g.room_cfg) --让所有桌子共享配置
    g.sendConfig("set", "blind_cfg", g.blind_cfg)
    print("end loadConfig")
end




--清理空桌子
function Handler:clearIdleDesk()

end

--取桌子id
function Handler:createDeskId(rid, rtype)
    --没有就创建一个桌子
    self.index_id = self.index_id + 1
    if self.index_id > 10000 then
        self.index_id = 10
    end
    return  rtype.. "_".. rid.."_" ..self.index_id .."_" ..g.getNodeId() .."_" ..self.start_time
end

--创建一个桌子
function Handler:createDesk(rid, rtype)
    rtype = rtype or 0
    local tid = self:createDeskId(rid, rtype)
    local service = g.newService("games.texas.service", tid, rid, rtype)
    if not service then
        g.log:err("newService games.texas.service", tid, rid, rtype)
        return
    end
    --桌子对象
    g.desks[tid] = { service = service,
                     tid = tid, rid = rid,
                     rtype = rtype,
                     user_num = 0,
                     seat_num = 0,
                     create_time = g.time(),
                     robot_num = 0,
    }
    g.call(service, "start")

    g.dp:setTables(tid)
    return g.desks[tid]
end

function Handler:delDesk(tid)
    if not tid then return end
    self:callTable(tid, "close")
    g.desks[tid] = nil

    g.dp:delTables(tid)
end

--匹配一个桌子
function Handler:reqEnterDesk(msg)
    g.log:info("reqEnterDesk: ", msg)
    if self.closed then
        g.log:warn("game is close!")
        return
    end
    if not msg.rtype and not msg.rid and not msg.tid then
        g.log:err("reqEnterDesk param err", msg)
        return {code=g.error_code.input_err}
    end
    local uid = msg.mid
    if not msg.rtype then
        msg.rtype = 0 --房间类型
    end
    if not uid then
        g.log:err("enterDesk uid err nil")
        return {code=g.error_code.invalid_mid}
    end
    if msg.tid and msg.tid ~= "" then
        --重连到指定桌子
        local str_tid = msg.tid
        local rtype = string.match(str_tid, "(%d)_.*") --这个是string类型
        local rid = string.match(str_tid, "%d_(%d+)_.*")
        local old_desk = self:getUserDesk(uid, rid, rtype)
        if old_desk then
            g.log:info("reqEnterDesk has old desk:", old_desk)
            msg.rtype = tonumber(rtype)
            msg.rid = tonumber(rid)
            msg.tid = old_desk.tid
            return self:enterDesk(old_desk, msg)
        end
        return self:enterDesk(g.desks[msg.tid], msg)
    end
    --在同一类型房间里只能进一个桌子
    local old_desk = self:getUserDesk(uid, msg.rid, msg.rtype)
    if old_desk then
        return self:enterDesk(old_desk, msg)
    end
    --最多只能进行两个桌子同时
    --取mid所在的桌子
    local tids = self:onGetUserDesks(uid)
    if #tids == 2 then
        if msg.tid and table.has(tids, msg.tid) then
        else
            return {code=g.error_code.in_too_tables}
        end
    end

    if msg.rtype == g.const.room_type.match then
        --比赛场
        return g.manager:enterMatchDesk(msg)
    end

    g.log:err("math_handler enter err!", msg)
    return {code=g.error_code.fail}
end

function Handler:enterDesk(desk, msg)
    if not desk or not desk.service then
        --服务不存在
        g.log:err("match enterDesk no service: ", desk, msg)
        return {code = g.error_code.game_over}
    end
    local uid = msg.mid
    if msg.rtype == g.const.room_type.match then
        --比赛场
        msg.match_rank = g.manager:getMatchRank(desk.rid, uid)
    end
    local res = g.call(desk.service, "enter_desk", msg) --玩家进入桌子请求
    if res then
        self:bindUserDesk(uid, desk.tid)
    end
    return res
end

--绑定玩家与桌子
function Handler:bindUserDesk(uid, tid)
    if not g.user_desk[uid] then
        g.user_desk[uid] = {}
    end
    for _, v in pairs(g.user_desk[uid]) do
        if v == tid then
            --已经存在就不用插入了
            return
        end
    end
    g.log:debug("bindUserDesk:", uid, tid)
    table_insert(g.user_desk[uid], tid)
end

--解绑玩家离与桌子
function Handler:unbindUserDesk(uid, tid)
    local tb = g.user_desk[uid]
    if not tb then
        return
    end
    for k, v in pairs(tb) do
        if v == tid then
            g.log:debug("unbindUserDesk:", uid, tid)
            table.remove(tb, k)
            return true
        end
    end
end

--合桌后
function Handler:onMergeDesk(msg)
    local uid = msg.mid
    local tid = msg.tid
    self:bindUserDesk(uid, tid)
end

--玩家在指定房间里的桌子
function Handler:getUserDesk(uid, rid, rtype)
    local tids = g.user_desk[uid] or {}
    g.log:info("getUserDesk tids:", uid, tids, rid, rtype)
    rid = tonumber(rid)
    rtype = tonumber(rtype)
    for _, tid in pairs(tids) do
        local desk = g.desks[tid]
        --g.log:warn("2222222222", desk.rid == rid , desk.rtype == rtype, desk.rid, rid , desk.rtype, rtype, type(desk.rid), type(rid) , type(desk.rtype), type(rtype) )
        if desk and desk.rid == rid and desk.rtype == rtype then
            return desk
        end
    end
end

--往桌子里发消息
function Handler:callTable(tid, ...)
    local tb = g.desks[tid]
    if not tb or not tb.service then
        --服务不存在
        g.log:err("callTable no service: ", tid, ...)
        return {code = g.error_code.game_over}
    end
    return g.call(tb.service, ...)
end

function Handler:sendTable(tid, ...)
    local tb = g.desks[tid]
    if not tb or not tb.service then
        --服务不存在
        g.log:err("sendTable no service ", tid, ...)
        return
    end
    return g.send(tb.service, ...)
end


--------------------------------------------
---
--------------------------------------------
--默认游戏消息处理
function Handler:defaultCallback(msg_name, msg)
    if not msg_name or type(msg)~="table" or not msg or not msg.tid then
        g.log:error("msg or tid is nil", msg_name, msg)
        return
    end
    --if self.closed then
    --    g.log:warn("games closeed: ", msg_name, msg)
    --    return
    --end
    return self:callTable(msg.tid, msg_name, msg)
end

--玩家离开桌子
function Handler:onUserLeave(tid, uid, rid)
    self:unbindUserDesk(uid, tid)
    g.log:debug("onUserLeave", tid, uid, rid)
    --if rid then
    --    local room = g.manager:getMatchRoom(rid)
    --    if room then
    --        g.log:debug("2onUserLeave", tid, uid, rid)
    --        g.dp:clearMatchUser(rid, tid, uid)
    --    end
    --end
end

--取玩家所在桌子
function Handler:onGetUserDesks(uid)
    local tids = {}
    local ids = g.user_desk[uid] or {}
    for _, tid in pairs(ids) do
        if g.desks[tid] then
            table_insert(tids, tid)
        end
    end
    if next(tids) then
        g.log:info("onGetUserDesks2:", uid, tids)
    end
    return tids
end

--玩家登录
function Handler:onUserLogin(uid)
    g.timeout(3, function()
        g.manager:checkUserMatch(uid)
    end)
    return true
end

--玩家离线了
function Handler:onDisconnect(msg)
    local uid = msg.uid
    if not uid then return true end
    local tids = g.user_desk[uid]
    if not tids then
        return true
    end
    if not next(tids) then --删除不在桌子的
        g.user_desk[uid] = nil
        return true
    end
    for _, tid in pairs(tids) do
        local tb = g.desks[tid]
        if not tb or not tb.service then
            --服务不存在
        else
            print("games disconnect:", tb.service, tid, uid)
            g.send(tb.service, "disconnect", msg)
        end
    end
    return true
end


--[[ desk = {
    service = service,
    id = tid,
    rid = rid,
    rtype=rtype,
    user_num = 0, 总人数
    seat_num
    }
--]]
--更新桌子信息
function Handler:onUpdateDesk(tid, msg)
    local desk = g.desks[tid]
    if not desk then return end
    for k, v in pairs(msg) do
        desk[k] = v
    end
end

--关闭游戏
function Handler:onClose(desk_id)
    if desk_id and desk_id ~= "" then
        --关闭指定桌子
        for tid, _ in pairs(g.desks) do
            if desk_id == tid then
                self:delDesk(tid)
                break
            end
        end
    else
        --关闭所有游戏
        self.closed = true
        for tid, _ in pairs(g.desks) do
           self:delDesk(tid)
        end
    end
end

function Handler:onKickUser(msg)
    if not msg or type(msg)~="table" then return end
    local uid = msg.uid
    if not uid then return end
    local tids = g.user_desk[uid]
    if not tids then
        return
    end
    for _, tid in pairs(tids) do
        local tb = g.desks[tid]
        if not tb or not tb.service then
            --服务不存在
        else
            g.log:info("games onKickUser:", tb.service, tid, uid)
            g.send(tb.service, "kick_user", uid)
        end
    end
end


return Handler
